/**
 * @author：anlzou
 * @Date：Created in21:02 2021/4/12
 * @Github：https://github.com/anlzou
 * @Description：
 */
package com.anlzou.code;

import com.anlzou.utlis.CreateDir;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;


/**
 * java中创建文件的五种方法：
 *      1. Files.newBufferedWriter(Java 8)
 *      2. Files.write(Java 7 推荐)
 *      3. PrintWriter
 *      4. File.createNewFile
 *      5. FileOutputStream.write(byte[] b) 管道流
 *
 * ---------------------
 *
 * java.nio.file.Files
 *      public final class Files extends Object
 *      该类只包含对文件，目录或其他类型文件进行操作的静态方法。
 *
 * -----------
 *
 * java.nio.file.Paths
 *      public final class Paths extends Object
 *      此类仅由静态方法组成，通过转换路径字符串返回Path或URI 。
 *
 * -----------
 *
 * java.io.PrintWriter
 *      public class PrintWriter extends Writer
 *      1. 将对象的格式表示打印到文本输出流。 这个类实现了全部在发现print种方法PrintStream 。 它不包含用于编写原始字节的方法，程序应使用未编码的字节流。
 *      2. 不像PrintStream类，如果启用自动刷新，它只会在调用的println，printf，或format方法来完成，而不是当一个换行符恰好是输出。 这些方法使用平台自己的行分隔符而不是换行符。
 *      3. 这个类中的方法不会抛出I / O异常，尽管它的一些构造函数可能。 客户可以通过调用checkError()查询是否发生错误。
 *
 * -----------
 *
 * java.io.File
 *      public class File extends Object implements Serializable, Comparable<File>
 *      文件和目录路径名的抽象表示。
 *
 * ---------------------
 */
public class CreateFile5Mode {

    //方式 1
    void createFile1() throws IOException {
        //输出文件夹
        String dirName = "output";
        //输出完整路径
        String fileName = "output/newFile01.txt";
        //输出文件路径，如果文件夹不存在则创建
        new CreateDir(dirName);

        Path path = Paths.get(fileName);
        /**
         * 使用newBufferedWriter创建文件并写文件
         * 这里使用了try-with-resources方法来关闭流，不用手动关闭
         *
         * public static BufferedReader newBufferedReader(Path path)
         *                                         throws IOException
         *
         * 打开一个文件进行阅读，返回一个BufferedReader以高效的方式从文件读取文本。 使用UTF-8 charset将文件中的字节解码为字符 。
         */
        try (BufferedWriter writer =
                     Files.newBufferedWriter(path,
                             StandardCharsets.UTF_8)) {
            writer.write("【01】Hello World -创建文件!!\n");
        }

        //追加写模式
        try (BufferedWriter writer =
                     Files.newBufferedWriter(path,
                             StandardCharsets.UTF_8,
                             StandardOpenOption.APPEND)) {
            writer.write("【01】Hello World -字母哥!!\n");
        } finally {
            System.out.println("写入成功");
        }
    }


    //方式 2
    void createFile2() throws IOException {
        //输出文件夹
        String dirName = "output";
        //输出完整路径
        String fileName = "output/newFile02.txt";
        //输出文件路径，如果文件夹不存在则创建
        new CreateDir(dirName);

        /**
         * 从JDK1.7开始提供的方法
         * 使用Files.write创建一个文件并写入
         *
         * public static Path write(Path path,
         *                          Iterable<? extends CharSequence> lines,
         *                          OpenOption... options)
         *                   throws IOException
         * 将文本行写入文件。 使用UTF-8 charset将字符编码为字节。
         *
         * 这个方法的工作原理就像调用它相当于评估表达式：
         *
         *    Files.write(path, lines, StandardCharsets.UTF_8, options);
         * 参数
         * path - 文件的路径
         * lines - 一个遍历char序列的对象
         * options - 指定文件打开方式的选项
         */
        Files.write(Paths.get(fileName),
                "【02】Hello World -创建文件!!\n".getBytes(StandardCharsets.UTF_8));

        // 追加写模式
        Files.write(Paths.get(fileName),
                "【02】Hello World -字母哥!!\n".getBytes(StandardCharsets.UTF_8),
                StandardOpenOption.APPEND);
    }


    //方式 3
    void createFile3() throws IOException {
        //输出文件夹
        String dirName = "output";
        //输出完整路径
        String fileName = "output/newFile03.txt";
        //输出文件路径，如果文件夹不存在则创建
        new CreateDir(dirName);

        /**
         * JDK 1.5开始就已经存在的方法
         *
         * public PrintWriter(File file,
         *                    String csn)
         *             throws FileNotFoundException,
         *                    UnsupportedEncodingException
         * 使用指定的文件和字符集创建一个新的PrintWriter，而不需要自动进行线条刷新。 这个方便的构造函数创建必要的中间体OutputStreamWriter ，它将使用提供的字符集对字符进行编码。
         *
         * 参数
         *      file - 用作此作者的目的地的文件。 如果文件存在，那么它将被截断为零大小; 否则，将创建一个新文件。 输出将被写入文件并进行缓冲。
         *      csn - 支持的名称charset
         */
        try (PrintWriter writer = new PrintWriter(fileName, "UTF-8")) {
            writer.println("【03】Hello World -创建文件!!");
            writer.println("【03】Hello World -字母哥!!");
        } finally {
            System.out.println("创建成功");
        }

        // Java 10进行了改进，支持使用StandardCharsets指定字符集，无法追加写入
        try (PrintWriter writer = new PrintWriter(fileName, StandardCharsets.UTF_8)) {
            writer.println("【03】first line!");
            writer.println("【03】second line!");
        } finally {
            System.out.println("创建成功");
        }

    }


    //方式 4
    void createFile4() throws IOException {
        //输出文件夹
//        String dirName = "output";
        //输出完整路径
        String fileName = "output/newFile04.txt";
        //输出文件路径，如果文件夹不存在则创建
//        new CreateDir(dirName);

        File file = new File(fileName);

        /**
         * 返回true表示文件成功
         * false 表示文件已经存在
         */
        if (file.createNewFile()) {
            System.out.println("创建文件成功！");
        } else {
            System.out.println("文件已经存在不需要重复创建");
        }

        // 使用FileWriter写文件
        try (FileWriter writer = new FileWriter(file)) {
            writer.write("【04】Hello World -创建文件!!");
        }

        // 无法追加
        try (FileWriter writer = new FileWriter(file)) {
            writer.write("【04】Second line text!!");
        }

    }


    //方式 5
    void createFile5() throws IOException {
        //输出文件夹
        String dirName = "output";
        //输出完整路径
        String fileName = "output/newFile05.txt";
        //输出文件路径，如果文件夹不存在则创建
        new CreateDir(dirName);

        /**
         * java.lang.Object
         *      java.io.OutputStream （这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。）
         *          java.io.ObjectOutputStream
         *          java.io.FileOutputStream
         *       java.io.Writer （用于写入字符流的抽象类。）
         *          java.io.OutputStreamWriter
         *          java.io.BufferedWriter
         *
         * -----------------
         *
         * public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants
         *      ObjectOutputStream将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取（重构）对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流，则可以在另一个主机上或另一个进程中重构对象。
         *      只有支持java.io.Serializable接口的对象才能写入流中。
         *
         * -----------------
         *
         * public class FileOutputStream extends OutputStream
         *      FileOutputStream用于写入诸如图像数据的原始字节流。 对于写入字符流，请考虑使用FileWriter 。
         *
         * -----------------
         *
         * public class OutputStreamWriter extends Writer
         *      OutputStreamWriter是字符的桥梁流以字节流：向其写入的字符编码成使用指定的字节charset 。
         *
         * -----------------
         *
         * public class BufferedWriter extends Writer
         *      将文本写入字符输出流，缓冲字符，以提供单个字符，数组和字符串的高效写入。
         */
        try (FileOutputStream fos = new FileOutputStream(fileName);
             OutputStreamWriter osw = new OutputStreamWriter(fos);
             BufferedWriter bw = new BufferedWriter(osw);) {
            bw.write("【05】Hello World -创建文件!!");
            bw.flush();
        }
    }

}
